package edu.nus.mtech.sem1.ca.main;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.nus.mtech.sem1.ca.Bill;
import edu.nus.mtech.sem1.ca.auth.AccessControlManager;
import edu.nus.mtech.sem1.ca.auth.User;
import edu.nus.mtech.sem1.ca.bill.BillReport;
import edu.nus.mtech.sem1.ca.bill.ReportModel;
import edu.nus.mtech.sem1.ca.cust.Customer;
import edu.nus.mtech.sem1.ca.cust.complaint.Complaint;
import edu.nus.mtech.sem1.ca.cust.complaint.ComplaintStatus;
import edu.nus.mtech.sem1.ca.data.Database;
import edu.nus.mtech.sem1.ca.data.DatabaseLoader;
import edu.nus.mtech.sem1.ca.exception.CustomerNotFoundException;
import edu.nus.mtech.sem1.ca.exception.NotAuthenticatedException;
import edu.nus.mtech.sem1.ca.exception.NotAuthorizedException;
import edu.nus.mtech.sem1.ca.exception.NotFoundException;
import edu.nus.mtech.sem1.ca.main.dao.TelephonyApplicationDao;
import edu.nus.mtech.sem1.ca.plan.Account;
import edu.nus.mtech.sem1.ca.plan.Plan;
import edu.nus.mtech.sem1.ca.utils.Common;
import edu.nus.mtech.sem1.ca.utils.Logger;
import edu.nus.mtech.sem1.ca.utils.TelephonyConstants;


/**
 * Serves as an entry point into the application
 *
 */
public class TelephoneApplication {
	private Database database;
	
	public TelephoneApplication(){
	
	}
	private TelephonyApplicationDao telephoneApplicationDao=new TelephonyApplicationDao();
	
	/**
	 * On authentication, the method will return an User object which encapsulates the UserRole class
	 * 
	 * @param username
	 * @param password
	 * @return
	 * @throws NotAuthenticatedException 
	 */
	public User login(String username, String password) throws NotAuthenticatedException{
		User user = telephoneApplicationDao.login(username, password);
		Common.USER_NAME=user.getUserName();
		Common.USER_ROLE=user.getUserRole();
		return user;
	}
	
	
	/**
	 * Returns the Customer object which encapsulates the Account and the Complaints object 
	 * 
	 * @param user - user who is logged in now (to check access control)
	 * @param nric - the nric of the customer which also serves as the unique identify of the customer
	 * @return
	 * @throws CustomerNotFoundException 
	 * @throws NotAuthorizedException 
	 */
	public Customer retrieveCustomerInfo(User user, String nric) throws CustomerNotFoundException, NotAuthorizedException{
		
		Customer customer=null;
		
		if (AccessControlManager.isUserAuthorized(user, TelephonyConstants.ACCESS_VIEW_CLIENT_DATA)){
			customer=telephoneApplicationDao.retrieveCustomerData(nric);
		}
		else{
			throw new NotAuthorizedException(TelephonyConstants.ERR_USER_NOT_AUTHORIZED_TO_VIEW_COMPLAINTS);
		}
		
		return customer;
		
	}
	
	/**
	 * Generates bill for an input customer. 
	 * @param user
	 * @param nric
	 * @param fromDate - this can only be a month beginning in this initial version of the app
	 * @param toDate - this can only be a month end 
	 * @throws Exception 
	 * @throws IllegalArgumentException 
	 */
	//Lai Oi Lye
	public void generateBill(Customer user, String nric, Date fromDate, Date toDate) throws IllegalArgumentException, Exception{

		Account account = new Account();
		String accountnos = user.getAccountNo();
		
		database=DatabaseLoader.getInstance().getDatabase();		
		Map<String, Account> accountMap = database.getAccountMap();
		if(accountMap.containsKey(accountnos)){
			account = accountMap.get(accountnos);
			Logger.log("Plan got it at TeleApp: " + account);
			Bill bill=new Bill();
			BillReport breport = new BillReport();
			
			breport.billToHtml(bill.calculateBill(user, account,fromDate,toDate));
			
		}
		else{
			Logger.log("No Valid Account for Billing");
			throw new CustomerNotFoundException("Not transaction is found for this client!");
			
		}
	}
	
	//Lai Oi Lye
	public void generateBillAll(Date fromDate, Date toDate) throws Exception{

		ArrayList<ReportModel> reportModels = new ArrayList<ReportModel>();
		database=DatabaseLoader.getInstance().getDatabase();
		// get customer Map and loop	
		Map<String, Account> accountMap = database.getAccountMap();		
		Map<String, Customer> customerMap = database.getCustomerMap();
		Set customerkey = customerMap.keySet();
		Iterator i = customerkey.iterator();
		String customerNRIC;
		Customer customer = new Customer();
		Account account = new Account();
		String accountnos = null;
		
		while(i.hasNext()){
			customerNRIC = (String) i.next();
			
			Logger.log(" !!!!! " + customerNRIC);
			if(customerMap.containsKey(customerNRIC)){
				customer=customerMap.get(customerNRIC);
				accountnos=customer.getAccountNo();
				
				if(accountMap.containsKey(accountnos)){
					Logger.log("&&&&& " + accountnos + customerNRIC);
					account = accountMap.get(accountnos);
					Bill bill = new Bill();
					reportModels.add(bill.calculateBill(customer, account,fromDate,toDate));
				}
				
			}
			
		}
		
		BillReport breport = new BillReport();
		
		breport.allBillsToHtml(reportModels);
		
		Iterator<ReportModel> t = reportModels.iterator();
		ReportModel r = new ReportModel();
		while(t.hasNext()){
			r= t.next();
			Logger.log("Customer Name : " + r.cust_Name +"---AccountNos:"+  r.cust_Account);
		}
		
		
			
	}
	

	/**
	 * Retrieves Set of complaints for a Customer
	 * @param user
	 * @param customer
	 * @return
	 * @throws NotAuthorizedException
	 * @throws NotFoundException
	 */
	public Set<Complaint> retrieveComplaintsForCustomer(User user, Customer customer) throws NotAuthorizedException, NotFoundException{
		
		Set<Complaint> complaints=null;
		//Alright. this should be simple
		if (customer!=null){
			if (AccessControlManager.isUserAuthorized(user, TelephonyConstants.ACCESS_VIEW_CLIENT_COMPLAINTS)){
				complaints=telephoneApplicationDao.retrieveComplaintsForCustomer(customer.getNric());
			}
			else{
				throw new NotAuthorizedException(TelephonyConstants.ERR_USER_NOT_AUTHORIZED_TO_VIEW_COMPLAINTS);
			}
		}
		else{
			throw new NotFoundException(TelephonyConstants.ERR_USER_IS_NULL);
		}
		
		return complaints;
	}
	
	/**
	 * Changes complaintStatus of the complaint. 
	 * @param customer
	 * @param complaint
	 * @param status
	 */
	public void changeComplaintStatus(Customer customer, Complaint complaint, ComplaintStatus status) {
	
		//set the status of the complaint
		if (complaint!=null){
			complaint.setStatus(status);
		}
		
		telephoneApplicationDao.addOrUpdateComplaintForCustomer(customer.getNric(),complaint);
		
	}
	
	
	/**
	 * Stores customer to the database
	 * @param customer
	 */
	public void registerCustomer(Customer customer){
		telephoneApplicationDao.registerCustomer(customer.getNric(), customer);
	}
	
	public void deRegisterCustomer(String nric){
		telephoneApplicationDao.deRegisterCustomer(nric);
	}


	public void saveAccountForCustomer(String nric, Account account) {

		telephoneApplicationDao.saveAccountForCustomer(nric, account);
	}
}
